package com.maowu.pooling.test;

import java.util.ArrayList;
import java.util.Vector;

import junit.framework.TestCase;

import com.maowu.pooling.FailedToConnectException;
import com.maowu.pooling.PoolErrorException;
import com.maowu.pooling.SimplePool;
import com.maowu.pooling.WaitingTimeoutException;

public class SimplePoolTestEx extends TestCase
{
    private SimplePool<MyConnectionStub> pool;
    private MyConnectionStubFactory factory;
    
    
    
    public void setUp() throws Exception
    {
        factory = new MyConnectionStubFactory();
        pool = new SimplePool<MyConnectionStub>(factory);
    }

   
    public void tearDown() throws Exception
    {
        pool.close();
    }
    
   
    public void testDisconnected() throws FailedToConnectException, WaitingTimeoutException, PoolErrorException
    {

            pool.setMaxConnection(1);
            MyConnectionStub conn = pool.borrowConnection();
            
            conn.setConnected(false);
            pool.returnConnection(conn);
            conn.setConnected(false);
            MyConnectionStub newConn = pool.borrowConnection();
            assertSame(conn, newConn);
            assertTrue(conn.isConnected());
            
            assertEquals(1, pool.getLent());
        
        
    }
    
    public void testFactoryReturnNull() throws FailedToConnectException, WaitingTimeoutException
    {
        factory.setReturnNull(true);
        try
        {
            pool.borrowConnection();
            fail("PoolErrorException should be shown.");
        }
        catch (PoolErrorException e)
        {
            e.printStackTrace();
            System.out.println("e.getMessage()=" + e.getMessage());
            assertTrue(e.getMessage().contains("ConnectionFactory return null at createConnection"));
        }
        
        assertEquals(0, pool.getLent());
        
    }
    

    public void testWaitingTimeout()
    {
        Object obj;
        pool.setWaitingTimeout(1000);
        pool.setMaxConnection(1);
        long start  = 0;
        try
        {
            obj = pool.borrowConnection();
             start = System.currentTimeMillis();
            pool.borrowConnection();
            fail("WaitingTimeoutException expected.");
        }
        catch (WaitingTimeoutException e)
        {
            long end = System.currentTimeMillis();
            System.out.println("end - start=" + (end - start));
            assertTrue(end - start < 1100);
            assertTrue(end - start > 900);

//            e.printStackTrace();
        }
        catch (Exception e)
        {
            assertNull(e);
        }
        
        assertEquals(1, pool.getLent());
        
    }    

    public void testWaitingTimeout2() throws InterruptedException, PoolErrorException
    {
        
        pool.setWaitingTimeout(10000000);
        pool.setMaxConnection(1);
        final ArrayList error = new ArrayList();
        final ArrayList obj = new ArrayList<Object>();
        Thread other = new Thread()
        {
            public void run()
            {
                long start = 0;
                try
                {
                    obj.add(pool.borrowConnection());
                    start = System.currentTimeMillis();
                    obj.add(pool.borrowConnection());
                    error.add(new Object());
                }
                catch (WaitingTimeoutException e)
                {
                }
                catch (Exception e)
                {
                    error.add(e);
                }
            }
        }; 
        other.start();
        Thread.sleep(1000);
        other.interrupt();
        assertEquals(0, error.size());
        assertEquals(1, pool.getLent());
        
        pool.returnConnection((MyConnectionStub) obj.get(0));
        assertEquals(0, pool.getLent());
        
    }
    
    public void testFactoryReturnNull2() throws FailedToConnectException, WaitingTimeoutException, PoolErrorException
    {
        MyConnectionStub conn = pool.borrowConnection();
        conn.setDamaged(true);
        pool.returnConnection(conn);
        
        
        
        factory.setReturnNull(true);
        try
        {
            pool.borrowConnection();
            fail("PoolErrorException should be shown.");
        }
        catch (PoolErrorException e)
        {
            e.printStackTrace();
            assertTrue(e.getMessage().contains("ConnectionFactory return null at createConnection"));
        }
        
        assertEquals(0, pool.getLent());
        
    }
    public void testFailToConnect() throws FailedToConnectException, WaitingTimeoutException, PoolErrorException
    {
        pool.setMaxConnection(1);
        factory.setFailedToConnect(true);
        try
        {
            pool.borrowConnection();
            fail("FailedToConnectException should be shown.");
        }
        catch (FailedToConnectException e)
        {
        }
        factory.setFailedToConnect(false);
        MyConnectionStub conn = pool.borrowConnection();
        assertNotNull(conn);
        
        assertEquals(1, pool.getLent());
        
    }
    
    
    public void testFailedToTouchConnection() throws FailedToConnectException, WaitingTimeoutException, PoolErrorException
    {
        MyConnectionStub conn = pool.borrowConnection();
//        conn.setDamaged(true);
        pool.returnConnection(conn);
        
        
        conn.setConnected(false);
        conn.setFailedToConnect(true);
        try
        {
            pool.borrowConnection();
            fail("FailedToConnectException should be shown.");
        }
        catch (FailedToConnectException e)
        {

        }
        
        assertEquals(0, pool.getLent());
    }
    
    public void testLuckly()
    {
        pool.setMaxConnection(1);
        pool.setWaitingTimeout(10000);
        final Vector finished = new Vector();
        final Vector<Exception> fail = new Vector<Exception>();
        for (int i = 0; i < 2; i++)
        {
            new Thread()
            {
                public void run()
                {
                    try
                    {
                        try
                        {
                            Thread.sleep(1000);
                        }
                        catch (InterruptedException e)
                        {
                            // 
                            e.printStackTrace();
                        }
                        for (int j = 0; j < 1000; j++)
                        {
                            Object obj = pool.borrowConnection();
                            try
                            {
                                Thread.sleep(1);
                            }
                            catch (InterruptedException e)
                            {
                                // 
                                e.printStackTrace();
                            }
                            pool.returnConnection((MyConnectionStub) obj);
                        }
                    }
                    catch (WaitingTimeoutException e)
                    {
                        e.printStackTrace();
                        fail.add(e);
                    }
                    catch (FailedToConnectException e)
                    {
                        // 
                        e.printStackTrace();
                        fail.add(e);
                    }

                    catch (PoolErrorException e)
                    {
                        // 
                        e.printStackTrace();
                        fail.add(e);
                    }
                    finished.add(Thread.currentThread());
                    
                }
            }.start();
        }
        assertEquals(0, pool.getLent());
        while(finished.size() != 2)
        {
            try
            {
                Thread.sleep(100);
                if (fail.size() != 0)
                {
                    fail.get(0).printStackTrace();
                    fail(fail.get(0).toString());
                }
            }
            catch (InterruptedException e)
            {
                fail(e.getMessage());
            }
        }
        
    }

    
    public void testConnectionDamaged()
    {
        try
        {
            pool.setMaxConnection(1);
            MyConnectionStub conn = pool.borrowConnection();
            
            conn.setDamaged(true);
            pool.returnConnection(conn);
            MyConnectionStub newConn = pool.borrowConnection();
            assertFalse(conn == newConn);
            assertTrue(conn.isConnected());
            
            assertEquals(1, pool.getLent());
            
        }
        catch (FailedToConnectException e)
        {
            assertNull(e);
            
        }
        catch (WaitingTimeoutException e)
        {
            assertNull(e);
        }
        catch (PoolErrorException e)
        {
            assertNull(e);
        }
        
    }

}
